<!--
 * @Author: rxn 1003312535@qq.com
 * @Date: 2024-07-05 15:25:53
 * @LastEditors: rxn 1003312535@qq.com
 * @LastEditTime: 2024-07-25 14:11:18
 * @FilePath: \vue3-progect\src\views\example\three\geometry\index.vue
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
-->
<!--缓存几何-->
<template>
	<div id="map"></div>
	<div id="tooltip"></div>
</template>

<script setup>
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import Stats from "three/addons/libs/stats.module.js";
// 引入dat.gui.js的一个类GUI
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
import * as d3 from "d3";
import { onMounted } from "vue";

onMounted(() => {
	let container = document.getElementById("map");
	const obj = new Panzer(container, { axesHelper: true });
});
class Panzer {
	constructor(container, option = {}) {
		this.container = container;
		this.option = option;
		this.offsetXY = d3.geoMercator();
		this.init();
	}
	init() {
		this.scene = new THREE.Scene();
		this.setCamera();
		this.setRenderer();
		this.animate(this.scene, this.camera);
		this.createPlane();
		this.createPanZer();
		this.createGUI();
		this.initHelper();
		this.otherConfig();
	}
	createGUI() {
		this.gui = new GUI();
		//改变交互界面style属性
		this.gui.domElement.style.right = "0px";
		this.gui.domElement.style.width = "300px";
		const obj = {
			x: 30,
			y: 60,
			z: 300
		};
		// gui界面上增加交互界面，改变obj对应属性
		this.gui.add(this.targetMesh.position, "x", 0, 100);
		this.gui.add(this.targetMesh.position, "y", 0, 50);
		this.gui.add(this.targetMesh.position, "z", 0, 60);
	}
	otherConfig() {
		this.setAmientLight();

		const directionalLight = new THREE.DirectionalLight(0xe8eaeb, 3);
		directionalLight.position.set(0, 10, 15);
		const directionalLight2 = directionalLight.clone();
		directionalLight2.position.set(-10, 10, 5);
		const directionalLight3 = directionalLight.clone();
		directionalLight3.position.set(5, 20, 20);
		const directionalLight4 = directionalLight.clone();
		directionalLight4.position.set(-5, 20, 40);
		this.scene.add(directionalLight);
		this.scene.add(directionalLight2);
		this.scene.add(directionalLight3);
		this.scene.add(directionalLight4);
	}

	setCamera() {
		this.camera = new THREE.PerspectiveCamera(
			90,
			this.container.offsetWidth / this.container.offsetHeight,
			0.1,
			1000
		);
		this.camera.position.set(8, 4, 10).multiplyScalar(2);
		this.camera.lookAt(0, 0, 0);
	}
	setRenderer() {
		this.renderer = new THREE.WebGLRenderer();
		this.renderer.setSize(
			this.container.offsetWidth,
			this.container.offsetHeight
		);
		this.renderer.setClearColor(0x444444, 1); //设置背景颜色
		this.container.appendChild(this.renderer.domElement);

		//创建stats对象
		this.stats = new Stats();
		console.log(this.stats, "stats");
		this.stats.setMode(0); //默认模式
		this.stats.domElement.style =
			"position: absolute; top: 0px; left: 0px; cursor: pointer; opacity: 0.9; z-index: 10000;"; //默认模式
		//stats.domElement:web页面上输出计算结果,一个div元素，
		this.container.appendChild(this.stats.domElement);
	}
	setAmientLight() {
		this.ambientLight = new THREE.AmbientLight(0xd4e7fd, 4);
		this.scene.add(this.ambientLight);
	}
	animate(scene, camera) {
		// console.log(scene, camera, "1");
		requestAnimationFrame(this.animate.bind(this, scene, camera));
		this.stats.update();
		this.render(scene, camera);
	}
	render(scene, camera) {
		this.renderer.render(scene, camera);
	}

	//创建平面
	createPlane() {
		const planeGeometry = new THREE.PlaneGeometry(50, 50);
		const groundMaterial = new THREE.MeshPhongMaterial({
			color: 0xcc8866,
			shininess: 20,
			slide: true
		});
		const groundMesh = new THREE.Mesh(planeGeometry, groundMaterial);
		groundMesh.rotation.x = Math.PI * -0.5;
		// this.scene.add(groundMesh);
	}
	//创建坦克对象
	createPanZer() {
		this.tank = new THREE.Object3D();
		this.scene.add(this.tank);
		this.carWidth = 4;
		this.carHeight = 1;
		this.carLength = 8;
		this.basePlateMesh = this.createBasePlate(
			this.carWidth,
			this.carHeight,
			this.carLength
		);
		this.tyreMesh = this.createTyre(
			this.carWidth,
			this.carHeight,
			this.carLength
		);
		this.tankHeadMesh = this.createTankHead();
		this.trankGanMesh = this.createTankGan();
		this.targetMesh = this.targetObject();
		this.createPath();
		this.tank.add(
			this.basePlateMesh,
			...this.tyreMesh,
			this.tankHeadMesh,
			this.trankGanMesh
		);
	}
	//创建底盘
	createBasePlate(carWidth, carHeight, carLength) {
		const geometry = new THREE.BoxGeometry(carWidth, carHeight, carLength);
		const material = new THREE.MeshPhongMaterial({ color: 0x6688aa });
		const mesh = new THREE.Mesh(geometry, material);
		mesh.position.y = 1;

		const tankCamera = this.craeteCamera(40, 2, 0.1, 1000);
		tankCamera.position.y = 3;
		tankCamera.position.z = -6;
		tankCamera.rotation.y = Math.PI;
		mesh.add(tankCamera);
		return mesh;

		// this.animate(this.scene, tankCamera);
	}
	//创建轮胎
	createTyre(carWidth, carHeight, carLength) {
		const wheelRadius = 1;
		const wheelThickness = 0.5;
		const wheelSegments = 36;
		const wheelGeometry = new THREE.CylinderGeometry(
			wheelRadius,
			wheelRadius,
			wheelThickness,
			wheelSegments
		);
		const material = new THREE.MeshPhongMaterial({ color: 0x888888 });
		const wheelPositions = [
			[-carWidth / 2 - wheelThickness / 2, 1, carLength / 3],
			[carWidth / 2 + wheelThickness / 2, 1, carLength / 3],
			[-carWidth / 2 - wheelThickness / 2, 1, 0],
			[carWidth / 2 + wheelThickness / 2, 1, 0],
			[-carWidth / 2 - wheelThickness / 2, 1, -carLength / 3],
			[carWidth / 2 + wheelThickness / 2, 1, -carLength / 3]
		];
		let result = [];
		wheelPositions.forEach((position) => {
			const mesh = new THREE.Mesh(wheelGeometry, material);
			mesh.position.set(...position);
			mesh.rotation.z = Math.PI * -0.5;
			result.push(mesh);
		});
		return result;
	}
	//创建坦克头
	createTankHead() {
		const radius = 2;
		const widthSegments = 32;
		const heightSegments = 16;
		const phiStart = 0;
		const phiLength = Math.PI * 2;
		const thetaStart = 0;
		const thetaLength = Math.PI / 2;
		const geometry = new THREE.SphereGeometry(
			radius,
			widthSegments,
			heightSegments,
			phiStart,
			phiLength,
			thetaStart,
			thetaLength
		);
		const material = new THREE.MeshPhongMaterial({ color: 0x6688aa });
		const mesh = new THREE.Mesh(geometry, material);
		mesh.position.y = 1.5;
		return mesh;
	}
	createTankGan() {
		// 炮干
		const turretWidth = 0.5;
		const turretHeight = 0.5;
		const turretLength = 5;
		const turretGeometry = new THREE.BoxGeometry(
			turretWidth,
			turretHeight,
			turretLength
		);
		const material = new THREE.MeshPhongMaterial({ color: 0x6688aa });
		const turretMesh = new THREE.Mesh(turretGeometry, material);
		const turretPivot = new THREE.Object3D();
		turretPivot.position.y = 2;
		turretMesh.position.z = turretLength * 0.5;
		turretPivot.add(turretMesh);
		return turretPivot;
	}
	targetObject() {
		// 目标
		const targetGeometry = new THREE.SphereGeometry(0.5, 36, 36);
		const targetMaterial = new THREE.MeshPhongMaterial({
			color: 0x00ff00,
			flatShading: true
		});
		const targetMesh = new THREE.Mesh(targetGeometry, targetMaterial);
		const targetElevation = new THREE.Object3D();
		const targetBob = new THREE.Object3D();
		this.scene.add(targetElevation);
		targetElevation.position.z = this.carLength * 2;
		targetElevation.position.y = 8;
		targetElevation.add(targetBob);
		targetBob.add(targetMesh);

		// 获取目标全局坐标
		const targetPosition = new THREE.Vector3();
		targetMesh.getWorldPosition(targetPosition);
		// 炮台瞄准目标
		this.trankGanMesh.lookAt(targetPosition);
		// this.trankGanMesh.lookAt(100, 0, 0);
		return targetBob;
	}
	createPath() {
		// 绘制移动路径
		const curve = new THREE.SplineCurve([
			new THREE.Vector2(-10, 20),
			new THREE.Vector2(-5, 5),
			new THREE.Vector2(0, 0),
			new THREE.Vector2(5, -5),
			new THREE.Vector2(10, 0),
			new THREE.Vector2(5, 10),
			new THREE.Vector2(-5, 10),
			new THREE.Vector2(-10, -10),
			new THREE.Vector2(-15, -8),
			new THREE.Vector2(-10, 20)
		]);

		const points = curve.getPoints(50);
		const geometry = new THREE.BufferGeometry().setFromPoints(points);
		const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
		const splineObject = new THREE.Line(geometry, material);
		splineObject.rotation.x = Math.PI * 0.5;
		splineObject.position.y = 0.05;
		this.scene.add(splineObject);
	}
	//创建相机
	craeteCamera(fov, aspect, near, far) {
		const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
		return camera;
	}

	/**
	 * ---辅助功能
	 */
	//初始化辅助功能
	initHelper() {
		this.option.axesHelper && this.AxesHelper();
		!this.option.OrbitControlsHelper && this.OrbitControlsHelper();
	}
	//坐标轴
	AxesHelper() {
		const axesHelper = new THREE.AxesHelper(200);
		this.scene.add(axesHelper);
	}
	// 相机轨道运动
	OrbitControlsHelper() {
		const controls = new OrbitControls(this.camera, this.renderer.domElement);
		controls.update();
	}
}
</script>

<style lang="less" scoped>
#map {
	height: 100%;
}
#tooltip {
	position: absolute;
	z-index: 2;
	background: white;
	padding: 10px;
	border-radius: 2px;
	visibility: hidden;
}
</style>
